#include <sys/epoll.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <getopt.h>

#define MES_STR       "Hello world!"
#define MAX_EVENTS    512

void print_usage(char *progname)
{
	printf("%s usage: \n", progname);
//	printf("-i(--ipaddr): sepcify server IP address\n");
	printf("-p(--port): sepcify server port\n");
	printf("-h(--help): print this help information\n");

	return;
}

void set_socket_rlimit(void);

int main(int argc, char** argv)
{

	int            daemon_run = 0;
	int            i = 0;
	int            epfd = -1;
	struct         epoll_event  event;
	struct         epoll_event  epoll_array[MAX_EVENTS];
	int            events = -1;

	int            sockfd = -1;
	int            on = 1;
	int            BACKLOG = 1024;
	int            acfd = -1;
	int            rv = -1;
	int            ch = -1;
	socklen_t      cliaddr_len;
	int            PORT=0;
//	char           *ID
	char           buf[1024];
	struct         sockaddr_in serv_addr;
	struct         sockaddr_in cli_addr;
	struct         option opts[] ={
//	      	       {"ipaddr", required_argument,NULL,'i'},
		       {"port", required_argument,NULL,'p'},
		       {"help", no_argument,NULL,'h'},
		       {NULL, 0, NULL, 0}
	};

	while((ch=getopt_long(argc, argv, "i:p:h", opts, NULL)) != -1 )
	{
		switch(ch)
		{
//			case'i':
//				ID=optarg;
				break;
		       	case'p':
                                PORT=atoi(optarg);
                                break;
		       	case'h':
                                print_usage(argv[0]);
                                return 0;
		}
	}
	
	if(/*!ID ||*/ !PORT)
	{
		print_usage(argv[0]);
		return 0;
	}

	set_socket_rlimit();


	sockfd=socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd<0)
	{
		printf("Create socket filetrue: %s\n",strerror(errno));
		return -1;
	}
        printf("Create socket successful: %d\n",sockfd);

	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));


	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	rv=bind(sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr));
	if(rv<0)
	{
                printf("Bind filetrue: %s\n",strerror(errno));
                return -2;
        }
        printf("socket[%d] bind on port[%d] for all IP ok\n",sockfd,PORT);

	listen(sockfd, BACKLOG);

	if(daemon_run)
	{
		daemon(0,0);
	}

	if((epfd = epoll_create(MAX_EVENTS)) < 0)
	{
		printf("epoll_create failure:%s\n", strerror(errno));
		return -1;
	}
	printf("epoll_create epfd[%d] successful! \n",epfd);

	memset(&epoll_array, 0, sizeof(epoll_array));
	event.events  = EPOLLIN;
	event.data.fd = sockfd;
	rv = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);
	if(rv<0)
	{
		printf("epoll_ctl failure:%s\n", strerror(errno));
                return -2;
	}
	printf("epoll_ctl successful!\n");

	for( ; ; )
	{
		events = epoll_wait(epfd, epoll_array, MAX_EVENTS, -1);
		if(events<0)
		{
			printf("epoll_wait failure:%s\n", strerror(errno));
                        break;
		}
		else if(events==0)
		{
			printf("epoll get timeout!\n");
			continue;
		}
		printf("Accept [%d] events!\n",events);

		for(i=0; i<events; i++)
		{
			if(epoll_array[i].events&EPOLLERR||epoll_array[i].events&EPOLLHUP)
			{
				printf("error or disconnect!\n");
				epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
				close(epoll_array[i].data.fd);
				//break;
				continue;
			}
	
	
			if(epoll_array[i].data.fd == sockfd)
	          	{
		        	cliaddr_len = sizeof(cli_addr);
        			printf("Start waitting for accept new client...\n");
	        		acfd=accept(sockfd, (struct sockaddr*)&cli_addr,&cliaddr_len);
		         	if(acfd<0)
	         		{
		            		printf("Accept new cilent filetrue: %s or disconnect!\n",strerror(errno));
             				epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
             				close(epoll_array[i].data.fd);
                                        continue;

		        	}
           			else if(acfd==0)
	           		{
		         		printf("Get disconnect!\n");
			        	continue;
        			}
	            		else
           			{
	              			event.data.fd = acfd;
		               		event.events  = EPOLLIN;
           				if((rv=epoll_ctl(epfd, EPOLL_CTL_ADD, acfd, &event)) < 0)
			         	{
              					printf("add acfd to event failure:%s\n",strerror(errno));
	           				epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
		           			close(epoll_array[i].data.fd);
                                                continue;

			           	}
            				printf("add acfd successful!\n");
	               		}
         		}
	              	else
          		{
	          		printf("Writting for reading!\n ");
         			memset(&buf, 0, sizeof(buf));
	            		printf("Before read\n");
        			printf("epoll_fd:%d\n",epoll_array[i].data.fd);
	           		rv=read(epoll_array[i].data.fd, buf, sizeof(buf));
		        	printf("After read\n");
           			if(rv<0)
	        		{
		         		printf("Read from client [%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
                                        epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
                                        close(epoll_array[i].data.fd);
        				continue;
        			}
          			else if(rv==0)
	          		{
         				printf("Client connect to server get disconnect!\n");
                                        epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
                                        close(epoll_array[i].data.fd);
	        			continue;
        			}
           			printf("read from client data:%d\n",rv);
	            		printf("Read from client:%s\n",buf);
	
            			rv=write(epoll_array[i].data.fd,MES_STR, strlen(MES_STR));
	            		printf("rv:%d\n",rv);
          			if(rv<0)
	         		{
		           		printf("Write to client[%d:%d] filetrue: %s\n",cli_addr.sin_addr.s_addr,cli_addr.sin_port,strerror(errno));
			        	epoll_ctl(epfd, EPOLL_CTL_DEL, epoll_array[i].data.fd, NULL);
                                        close(epoll_array[i].data.fd);
          				continue;

         			}
         			printf("write to client data:%d\n",rv);
					
         		}
            	}
	}
CleanUp:
	close(epoll_array[i].data.fd);
	return 0;
}
 

void set_socket_rlimit(void)
{
	struct rlimit limit = {0};
	
	getrlimit(RLIMIT_NOFILE, &limit);
	limit.rlim_cur = limit.rlim_max;
	setrlimit(RLIMIT_NOFILE, &limit);

	printf("set socket open fd max count to %ld\n",limit.rlim_max);
}
















